/**
 * @file
 * @author  Daniel White
 * @version 0.1
 * @brief Set of (hopefully) fast maths functions that may help when developing a game.
 * @section Description
 * 
 * Set of (hopefully) fast maths functions that may help when developing a game. Contains various functions to do with primes, factors, trigonometry etc. Aims to be very fast.
 */


#ifndef MATH_HEADER
#define MATH_HEADER

/** Macro for converting degrees into radians. */
#define Math_DegToRad(D) ((D)*0.017453293)

/** Macro for converting radians into degrees. */
#define Math_RadToDeg(R) ((R)*57.295779513) 

/**
 * Decides if a given number is prime or not. Uses a small array of primes to check for factors, before resorting to an optomized trail-division algorithm if needed.
 * 
 * @param Number The number to check for primality.
 * @return 1 if the number is prime, 0 otherwise. 
 */
int Math_IsPrime(int Number);

/**
 * Fills an array with the first N primes. Uses an optomized sieve of Eratosthenes to generate the primes. Note: If memory is an issue, Math_GetFirstNPrimesLowMemory should be used instead.
 *
 * @param Amount Amount of primes to generate.
 * @param Array An array of ints where the primes will be stored. Note: It is the user's duty to ensure this is big enough.
 * @return 0 on success, -1 on failure. 
 */ 
int Math_GetFirstNPrimes(int Amount, int *Array);

/**
 * Fills an array with the first N primes. Uses an optomized trail-division method to decide if numbers are prime or not. Note: If memory is not an issue, Math_GetFirstNPrimes could be used instead (which is faster).
 *
 * @param Amount Amount of primes to generate.
 * @param Array An array of ints where the primes will be stored. Note: It is the user's duty to ensure this is big enough.
 * @return 0 on success, -1 on failure. 
 */ 
int Math_GetFirstNPrimesLowMemory(int Amount, int *Array);

/**
 * Computes the greatest common divisor (also known as the highest common factors) of two numbers. Uses the Euclidean algorithm to compute the GCD.
 *
 * @param Number0 The first number.
 * @param Number1 The second number.
 * @return The GCD of Number0 and Number1. 
 */
int Math_GCD(int Number0, int Number1);

/**
 * Computes the least common multiple (also known as the lowest common multiple) of two numbers.
 *
 * @param Number0 The first number.
 * @param Number1 The second number.
 * @return  The LCM of Number0 and Number1.
 */ 
int Math_LCM(int Number0, int Number1);

/**
 * Calculates the sum of digits in the given number (assuming base 10).
 *
 * @param Number The number whose digits will be added.
 * @return The sum of the digits.
 */
int Math_DigitalSum(int Number);

/**
 * Calculates the digital root of a number (repeated digit sum until the result is a single digit number).
 *
 * @param Number The number to find the digital root of.
 * @return The digital root.
 */
int Math_DigitalRoot(int Number);

/**
 * Takes an angle, and returns the displacement a particle would be displaced by in the X direction if its velocity was 1.
 *
 * @param Angle The angle in degrees where 0 is North and 90 is East.
 * @return The X displacement.
 */
inline float Math_AngleX(float Angle);

/**
 * Takes an angle, and returns the displacement a particle would be displaced by in the Y direction if its velocity was 1.
 *
 * @param Angle The angle in degrees where 0 is North and 90 is East.
 * @return The Y displacement.
 */
inline float Math_AngleY(float Angle);

/**
 * Calculates the angle to get from the start point (X1, Y1) to the end point (X2, Y2).
 *
 * @param X1 X co-ordinate of the start point.
 * @param Y1 Y co-ordinate of the start point.
 * @param X2 X co-ordinate of the end point.
 * @param Y2 Y co-ordinate of the end point.
 * @return The angle.
 */
inline float Math_XYAngle(float X1, float Y1, float X2, float Y2);

/**
 * Normalises an angle, i.e. adds/subtracts multiples of 360 so that it is in the range 0<=Angle<360.
 *
 * @param Angle The angle to normalise.
 * @return The normalised angle.
 */
float Math_NormaliseAngle(float Angle);

/**
 * Factorises a number into its prime factors.
 *
 * @param Number The number to factorise
 * @param Factors A pointer to an array of ints. This must be passed by reference because the function may need to realloc it to hold the factors, hence the array location might change.
 * @return On success the amount of factors is returned (>0), on failure -1 is returned. 
 */ 
int Math_PrimeFactors(int Number, int **Factors);

/**
 * Returns the amount of prime factors a number has.
 *
 * @param Number The number to count the factors for.
 * @return The amount of prime factors.
 */
int Math_PrimeFactorCount(int Number);

/**
 * Returns the amount of factors a number has (whether they be composite or prime).
 *
 * @param Number The number to count the factors for.
 * @return The amount of factors.
 */
int Math_FactorCount(int Number);

/**
 * When primes are generated with the GetFirstNPrimes() function, a cache of the primes is kept (if there is enough memory). This speeds up calls to many of the functions. However if the memory is needed, this function will clear the cache, freeing the memory used.
 */
void Math_ClearCache();

#endif
